package org.example.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.StrFormatter;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.example.entity.ProjectVersion;
import org.example.entity.ProjectVersionDetail;
import org.example.entity.ProjectVersionTranslateDetail;
import org.example.entity.dto.ProjectVersionCompareDTO;
import org.example.entity.dto.TranslateCompareDto;
import org.example.entity.vo.CompareDetailVo;
import org.example.enums.CompareDetailTypeEnum;
import org.example.mapper.ProjectVersionMapper;
import org.example.service.ProjectVersionDetailService;
import org.example.service.ProjectVersionService;
import org.example.service.ProjectVersionTranslateDetailService;
import org.example.utils.CenseUtils;
import org.example.utils.ChineseStringGeneratorUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
@Slf4j
public class ProjectVersionServiceImpl extends ServiceImpl<ProjectVersionMapper, ProjectVersion> implements ProjectVersionService {

    @Resource
    private ProjectVersionDetailService projectVersionDetailService;

    @Resource
    private ProjectVersionTranslateDetailService projectVersionTranslateDetailService;

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Override
    public void createVersion(String versionNo) {
        Optional<ProjectVersion> opt = lambdaQuery()
                .eq(ProjectVersion::getVersionNo, versionNo)
                .oneOpt();
        if(opt.isPresent()){
            throw new RuntimeException("版本已存在");
        }
        ProjectVersion projectVersion = new ProjectVersion();
        projectVersion.setVersionNo(versionNo);
        projectVersion.setCreateTime(LocalDateTime.now());
        projectVersion.setUpdateTime(LocalDateTime.now());
        boolean save = save(projectVersion);
        for (int i = 0; i < 2; i++) {
            int finalI = i;
            new Thread(()->{
                log.info("线程 {} 开始生成版本 {} 数据", finalI,projectVersion.getVersionNo());
                List<ProjectVersionDetail> details = IntStream.range(0, 10000).boxed()
                        .map(a -> {
                            ProjectVersionDetail build = ProjectVersionDetail.builder()
                                    .versionId(projectVersion.getId())
                                    .localism(ChineseStringGeneratorUtils.getRandomLocalism())
                                    .scene(CenseUtils.getScene())
                                    .build();
                            build.setCreateTime(LocalDateTime.now());
                            build.setUpdateTime(LocalDateTime.now());
                            build.setTranslateDetails(build.form());
                            return build;
                        })
                        .collect(Collectors.toList());

                projectVersionDetailService.saveBatch(details);

                List<ProjectVersionTranslateDetail> translateDetails = details.stream().filter(d -> !CollectionUtils.isEmpty(d.getTranslateDetails()))
                        .map(d -> {
                            d.getTranslateDetails().forEach(projectVersionTranslateDetail -> projectVersionTranslateDetail.setDetailId(d.getId()));
                            return d.getTranslateDetails();
                        }).flatMap(Collection::stream)
                        .collect(Collectors.toList());

                if(!CollectionUtils.isEmpty(translateDetails)){
                    projectVersionTranslateDetailService.saveBatch(translateDetails);
                }
                log.info("线程 {} 生成版本 {} 数据完成", finalI,projectVersion.getVersionNo());
            }).start();
        }
    }

    @Override
    public List<Long> compare(Long currentNo, Long historyNo) {
        long start = System.currentTimeMillis();
        List<ProjectVersionDetail> currents = getVersion(currentNo);
        List<ProjectVersionDetail> historys = getVersion(historyNo);
//        Map<String, List<ProjectVersionDetail>> map = CompletableFuture.supplyAsync(() -> getVersion(currentNo), threadPoolTaskExecutor)
//                .thenCombine(CompletableFuture.supplyAsync(() -> getVersion(historyNo), threadPoolTaskExecutor)
//                        , (currentData, historyData) -> {
//                            Map<String, List<ProjectVersionDetail>> result = new HashMap<>();
//                            result.put("current", currentData);
//                            result.put("history", historyData);
//                            return result;
//                        }).join();
//        List<ProjectVersionDetail> currents = map.get("current");
//        List<ProjectVersionDetail> historys = map.get("history");
        log.info("查询耗时 : {}  ; current : {} ; history : {} ",System.currentTimeMillis() - start,currents.size(),historys.size());

        long compareStart = System.currentTimeMillis();
//        Map<String, ProjectVersionDetail> currentMap = currents.parallelStream().collect(Collectors.toMap(p -> p.getLocalism() + "#" + p.getScene(), p -> p));
//        Set<String> historySet = historys.parallelStream().map(p -> p.getLocalism() + "#" + p.getScene()).collect(Collectors.toSet());

        Set<String> currentSet = currents.parallelStream().map(p -> p.getLocalism() + "#" + p.getScene()).collect(Collectors.toSet());

        Map<String,ProjectVersionDetail> historyMap = historys.parallelStream().collect(Collectors.toMap(p -> p.getLocalism() + "#" + p.getScene(),p-> p));

        // 当前版本有的 历史版本没有的
        List<ProjectVersionDetail> collect = currents.parallelStream()
                .filter(current -> !historyMap.containsKey(current.getLocalism() + "#" + current.getScene()))
                .collect(Collectors.toList());


        // 历史版本有的 当前版本没有的
        List<ProjectVersionDetail> dels = historys.parallelStream().filter(history -> !currentSet.contains(history.getLocalism() + "#" + history.getScene()))
                .collect(Collectors.toList());

        // 文言相同译文不同的
        List<ProjectVersionDetail> modify = currents.parallelStream().filter(current -> historyMap.containsKey(current.getLocalism() + "#" + current.getScene()))
                .filter(current -> {
                    ProjectVersionDetail history = historyMap.get(current.getLocalism() + "#" + current.getScene());
                    return compareTranslation(current.getTranslateDetails(), history.getTranslateDetails());
                }).collect(Collectors.toList());


//        List<ProjectVersionDetail> collect = currents.parallelStream()
//                .filter(current -> historys.parallelStream().noneMatch(history -> new EqualsBuilder().append(current.getLocalism(), history.getLocalism()).append(current.getScene(), history.getScene()).isEquals()))
//                .collect(Collectors.toList());
        log.info(" 比对耗时 : {}",System.currentTimeMillis() - compareStart);
        return collect.parallelStream().map(ProjectVersionDetail::getId).collect(Collectors.toList());
    }

    @Override
    public List<CompareDetailVo> compareDetail(ProjectVersionCompareDTO dto) {
        long queryStart = System.currentTimeMillis();
        List<ProjectVersionDetail> currentData = getVersion(dto.getCurrentVersionId());
        List<ProjectVersionDetail> historyData = getVersion(dto.getHistoryVersionId());
        log.info("查询耗时 : {} ; current : {} ; history : {}",System.currentTimeMillis() - queryStart,currentData.size(),historyData.size());

        long compareStart = System.currentTimeMillis();
        if(CollectionUtil.isNotEmpty(currentData) && CollectionUtil.isNotEmpty(historyData)){

            List<CompareDetailVo> result = new ArrayList<>();

            Map<String, ProjectVersionDetail> historyMap = historyData.stream().collect(Collectors.toMap(p -> p.getLocalism() + "#" + p.getScene(), p -> p));

            Map<String, ProjectVersionDetail> currentMap = currentData.stream().collect(Collectors.toMap(p -> p.getLocalism() + "#" + p.getScene(), p -> p));


            // 当前版本有的 历史版本没有的
            List<CompareDetailVo> adds = currentData.parallelStream()
                    .filter(current -> !historyMap.containsKey(current.getLocalism() + "#" + current.getScene()))
                    .map(p -> {
                        List<CompareDetailVo> compareDetailVos = compareTranslationVo(p.getTranslateDetails(), null);
                        if(CollectionUtil.isNotEmpty(compareDetailVos)){
                            compareDetailVos.forEach(t -> {
                                t.setLocalism(p.getLocalism());
                                t.setScene(p.getScene());
                            });
                        }
                        return compareDetailVos;
                    })
                    .filter(Objects::nonNull)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());


            //  历史版本有的 当前版本没有的
            List<CompareDetailVo> removes = historyData.parallelStream()
                    .filter(current -> !currentMap.containsKey(current.getLocalism() + "#" + current.getScene()))
                    .map(p -> {
                        List<CompareDetailVo> compareDetailVos = compareTranslationVo(null, p.getTranslateDetails());
                        if(CollectionUtil.isNotEmpty(compareDetailVos)){
                            compareDetailVos.forEach(t -> {
                                t.setLocalism(p.getLocalism());
                                t.setScene(p.getScene());
                            });
                        }
                        return compareDetailVos;
                    })
                    .filter(Objects::nonNull)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());

            // 当前版本有的 历史版本有的 但译文不同的
            List<CompareDetailVo> modifys = currentData.parallelStream()
                    .filter(current -> historyMap.containsKey(current.getLocalism() + "#" + current.getScene()))
                    .map(p -> {
                        ProjectVersionDetail history = historyMap.get(p.getLocalism() + "#" + p.getScene());
                        List<CompareDetailVo> compareDetailVos = compareTranslationVo(p.getTranslateDetails(), history.getTranslateDetails());
                        if(CollectionUtil.isNotEmpty(compareDetailVos)){
                            compareDetailVos.forEach(t -> {
                                t.setLocalism(p.getLocalism());
                                t.setScene(p.getScene());
                            });
                        }
                        return compareDetailVos;
                    })
                    .filter(Objects::nonNull)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());


            if(CollectionUtil.isNotEmpty(adds)){
                result.addAll(adds);
            }

            if(CollectionUtil.isNotEmpty(removes)){
                result.addAll(removes);
            }

            if(CollectionUtil.isNotEmpty(modifys)){
                result.addAll(modifys);
            }


        }else if(CollectionUtil.isNotEmpty(currentData)){

        }else if(CollectionUtil.isNotEmpty(historyData)){

        }
        log.info("比对耗时 : {}",System.currentTimeMillis() - compareStart);
        return null;
    }


    public List<ProjectVersionDetail> getVersion(Long versionId){

        return   CompletableFuture.supplyAsync(()->{
              return projectVersionDetailService
                      .lambdaQuery()
                      .select(ProjectVersionDetail::getId, ProjectVersionDetail::getLocalism, ProjectVersionDetail::getScene)
                      .eq(ProjectVersionDetail::getVersionId, versionId)
                      .list();
          },threadPoolTaskExecutor).thenCombine(CompletableFuture.supplyAsync(()->{

                      String sql = StrFormatter.format(" where detail_id in( select id from project_version_detail where version_id= {}  )", versionId);
                      //查询译文
                      List<ProjectVersionTranslateDetail> translations = projectVersionTranslateDetailService
                              .lambdaQuery()
                              .select(ProjectVersionTranslateDetail::getId, ProjectVersionTranslateDetail::getDetailId, ProjectVersionTranslateDetail::getTranslation, ProjectVersionTranslateDetail::getTargetLanguage)
                              .last(sql)
                              .list();
                      return translations;
                  },threadPoolTaskExecutor),(localisms,translates)->{

            long millis = System.currentTimeMillis();
            if(CollectionUtil.isNotEmpty(localisms) && CollectionUtil.isNotEmpty(translates)){
                  Map<Long, List<ProjectVersionTranslateDetail>> translateMap = translates.stream().collect(Collectors.groupingBy(ProjectVersionTranslateDetail::getDetailId));

                  localisms.forEach(projectVersionDetail -> {
                      projectVersionDetail.setTranslateDetails(translateMap.getOrDefault(projectVersionDetail.getId(),null));
                  });
              }
            log.info("查询解析耗时 : {}",System.currentTimeMillis() - millis);
              return localisms;
          }).join();
    }


    private boolean compareTranslation(List<ProjectVersionTranslateDetail> currentTranslation,List<ProjectVersionTranslateDetail> historyTranslation){

        if(CollectionUtil.isNotEmpty(currentTranslation) && CollectionUtil.isNotEmpty(historyTranslation)){
            JSONArray currentJson = TranslateCompareDto.form(currentTranslation);
            JSONArray historyJson = TranslateCompareDto.form(historyTranslation);
            return !currentJson.equals( historyJson);
        } else if (CollectionUtil.isNotEmpty(currentTranslation)) {
            return true;
        } else if(CollectionUtil.isNotEmpty(historyTranslation)){
            return true;
        }
        return false;
    }


    private List<CompareDetailVo> compareTranslationVo(List<ProjectVersionTranslateDetail> currentTranslation,List<ProjectVersionTranslateDetail> historyTranslation){

        if(CollectionUtil.isNotEmpty(currentTranslation) && CollectionUtil.isNotEmpty(historyTranslation)){
            List<CompareDetailVo> result = new ArrayList<>();
            Map<String, ProjectVersionTranslateDetail> historyMap = historyTranslation.stream().collect(Collectors.toMap(ProjectVersionTranslateDetail::getTargetLanguage, t -> t));
            Map<String, ProjectVersionTranslateDetail> currentMap = currentTranslation.stream().collect(Collectors.toMap(ProjectVersionTranslateDetail::getTargetLanguage, t -> t));
            List<CompareDetailVo> adds = currentTranslation.stream().filter(projectVersionTranslateDetail -> !historyMap.containsKey(projectVersionTranslateDetail.getTargetLanguage()))
                    .map(t -> CompareDetailVo.builder().targetLanguage(t.getTargetLanguage()).currentTranslation(t.getTranslation()).type(CompareDetailTypeEnum.add).build())
                    .collect(Collectors.toList());


            List<CompareDetailVo> removes = historyTranslation.stream().filter(t -> !currentMap.containsKey(t.getTargetLanguage()))
                    .map(t -> CompareDetailVo.builder().historyTranslation(t.getTranslation()).targetLanguage(t.getTargetLanguage()).type(CompareDetailTypeEnum.modify).build())
                    .collect(Collectors.toList());


            List<CompareDetailVo> modify = currentTranslation.stream().filter(t -> historyMap.containsKey(t.getTargetLanguage()))
                    .filter(t -> !t.getTranslation().equals(historyMap.get(t.getTargetLanguage()).getTranslation()))
                    .map(t -> {
                        ProjectVersionTranslateDetail history = historyMap.get(t.getTargetLanguage());
                        return CompareDetailVo.builder().type(CompareDetailTypeEnum.modify).currentTranslation(t.getTranslation()).targetLanguage(t.getTargetLanguage())
                                .historyTranslation(history.getTranslation())
                                .build();
                    })
                    .collect(Collectors.toList());


            if(CollectionUtil.isNotEmpty(adds)){
                result.addAll(adds);
            }

            if(CollectionUtil.isNotEmpty(removes)){
                result.addAll(removes);
            }

            if(CollectionUtil.isNotEmpty(modify)){
                result.addAll(modify);
            }
        } else if (CollectionUtil.isNotEmpty(currentTranslation)) {
            List<CompareDetailVo> adds = currentTranslation.stream().map(p -> CompareDetailVo.builder().currentTranslation(p.getTranslation()).targetLanguage(p.getTargetLanguage()).type(CompareDetailTypeEnum.add).build())
                    .collect(Collectors.toList());
            return adds;
        } else if(CollectionUtil.isNotEmpty(historyTranslation)){

            List<CompareDetailVo> removes = historyTranslation.stream().map(p -> CompareDetailVo.builder().currentTranslation(p.getTranslation()).targetLanguage(p.getTargetLanguage()).type(CompareDetailTypeEnum.remove).build())
                    .collect(Collectors.toList());
            return removes;
        }
        return null;
    }
}
